﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Unis.Framework.Core.Exceptions;
using Unis.Framework.Core.Log;
using Unis.Framework.Core.Utility;
using Unis.Framework.ORM.Common;
using Unis.Framework.ORM.DbSql;
using Unis.Framework.ORM.Emit;
using Unis.Framework.ORM.Mapping;
using Unis.Framework.ORM.Model;
using Unis.Framework.ORM.Persistence;
using Unis.Framework.ORM.Xml;
using Unis.Framework.RuleBase.Exceptions;
using Unis.ORM;
using Unis.ORM.DbSql;
using Unis.ORM.Mapping;
using Unis.ORM.Persistence;
using Unis.ORM.Xml;
using Unis.RuleBase.Exceptions;

namespace Unis.Framework.RuleBase.Common
{
    public class DatabaseExcuteByXmlHelper
    {
        // Fields
        private string[] _CommandTextFormatValues;
        private DatabaseExecuteHelper _DatabaseExecte;
        private PersistenceManagerHelper _PersistenceManager;

        //Properties
        /// <summary>
        /// 外部传入的链接字符串信息
        /// </summary>
        private OrmConnectionParams _ormP { get; set; }
        // Methods
        public DatabaseExcuteByXmlHelper()
        {
        }

        public DatabaseExcuteByXmlHelper(OrmConnectionParams ormp)
        {
            _ormP = ormp;
        }

        public DatabaseExcuteByXmlHelper(string[] commandTextFormatValues)
        {
            this._CommandTextFormatValues = commandTextFormatValues;
        }

        public int ExecuteNonQuery(string xmlFileName, string sqlName, params object[] parValues)
        {
            return this.ExecuteNonQuery(null, xmlFileName, sqlName, parValues);
        }

        public int ExecuteNonQuery(DbTransaction transaction, string xmlFileName, string sqlName, params object[] parValues)
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);
            if (this._PersistenceManager == null)
            {
                this._PersistenceManager = new PersistenceManagerHelper(this._CommandTextFormatValues);
            }
            DbCommand[] dbCmds = this._PersistenceManager.CreateDbCommandByXml(db, xmlFileName, sqlName, parValues);
            int num = 0;
            try
            {
                if (this._DatabaseExecte == null)
                {
                    this._DatabaseExecte = new DatabaseExecuteHelper();
                }
                num = (transaction == null) ? this._DatabaseExecte.ExecuteNonQuery(db, dbCmds) : this._DatabaseExecte.ExecuteNonQuery(db, dbCmds, transaction);
            }
            catch (Exception exception)
            {
                throw new DatabaseExecuteException("执行ExecuteNonQuery 出错！", exception);
            }
            finally
            {
                foreach (DbCommand command in dbCmds)
                {
                    command.Dispose();
                }
            }
            return num;
        }

        public int ExecuteNonQueryByEntity<T>(string xmFileName, string sqlName, T entity) where T : BaseModel
        {
            List<T> entitys = new List<T> { entity };
            return this.ExecuteNonQueryByEntity<T>(null, xmFileName, sqlName, entitys);
        }

        public int ExecuteNonQueryByEntity<T>(DbTransaction transaction, string xmFileName, string sqlName, IList<T> entitys) where T : BaseModel
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);
            List<DbCommand> list = new List<DbCommand>();
            foreach (T local in entitys)
            {
                if (this._PersistenceManager == null)
                {
                    this._PersistenceManager = new PersistenceManagerHelper(this._CommandTextFormatValues);
                }
                DbCommand[] collection = this._PersistenceManager.GetDbCommand(db, local, xmFileName, sqlName);
                list.AddRange(collection);
            }
            int num = 0;
            try
            {
                if (this._DatabaseExecte == null)
                {
                    this._DatabaseExecte = new DatabaseExecuteHelper();
                }
                num = (transaction == null) ? this._DatabaseExecte.ExecuteNonQuery(db, list.ToArray()) : this._DatabaseExecte.ExecuteNonQuery(db, list.ToArray(), transaction);
            }
            catch (Exception exception)
            {
                throw new DatabaseExecuteException("执行ExecuteNonQueryByEntity<T> 出错！", exception);
            }
            finally
            {
                foreach (DbCommand command in list)
                {
                    command.Dispose();
                }
            }
            return num;
        }

        public int ExecuteNonQueryBySqlParams(string xmlFileName, string sqlName, List<SqlParamInfo> sqlParams)
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);
            if (this._PersistenceManager == null)
            {
                this._PersistenceManager = new PersistenceManagerHelper(this._CommandTextFormatValues);
            }
            DbCommand[] dbCmds = this._PersistenceManager.CreateDbCommandBySqlParams(db, xmlFileName, sqlName, sqlParams);
            int num = 0;
            try
            {
                if (this._DatabaseExecte == null)
                {
                    this._DatabaseExecte = new DatabaseExecuteHelper();
                }
                num = this._DatabaseExecte.ExecuteNonQuery(db, dbCmds);
            }
            catch (Exception exception)
            {
                throw new DatabaseExecuteException("执行ExecuteNonQueryBySqlParams 出错！", exception);
            }
            finally
            {
                foreach (DbCommand command in dbCmds)
                {
                    command.Dispose();
                }
            }
            return num;
        }
        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="procName">存储过程名称</param>
        /// <param name="parameterValues">存错过程参数</param>
        /// <returns></returns>
        public DataSet ExecuteProc(string procName, params object[] parameterValues)
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);

            return DatabaseExcuteBySql.QuerybyProc(db, procName, parameterValues);
        }

        public T ExecuteScalar<T>(string xmlFileName, string sqlName, params object[] parValues)
        {
            return this.ExecuteScalar<T>(null, xmlFileName, sqlName, parValues);
        }

        public object ExecuteScalar(string xmlFileName, string sqlName, params object[] parValues)
        {
            return this.ExecuteScalar(null, xmlFileName, sqlName, parValues);
        }

        public T ExecuteScalar<T>(DbTransaction transaction, string xmlFileName, string sqlName, params object[] parValues)
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);
            if (this._PersistenceManager == null)
            {
                this._PersistenceManager = new PersistenceManagerHelper(this._CommandTextFormatValues);
            }
            DbCommand[] commandArray = this._PersistenceManager.CreateDbCommandByXml(db, xmlFileName, sqlName, parValues);
            if (commandArray.Length != 1)
            {
                throw new SelectSqlXmlConfigException(xmlFileName, sqlName);
            }
            DbCommand dbCmd = commandArray[0];
            TraceEx.Write("正在执行:" + DbCommandExecuteTrack.Instance.CommandToTrackMessage(db, dbCmd));
            object obj2 = null;
            try
            {
                obj2 = (transaction == null) ? db.ExecuteScalar(dbCmd) : db.ExecuteScalar(dbCmd, transaction);
            }
            catch (Exception exception)
            {
                throw new DatabaseExecuteException("执行ExecuteScalar 出错！", exception);
            }
            finally
            {
                foreach (DbCommand command2 in commandArray)
                {
                    command2.Dispose();
                }
            }
            if ((obj2 != null) && (obj2 != DBNull.Value))
            {
                return (T)Convert.ChangeType(obj2, typeof(T));
            }
            return default(T);
        }

        public object ExecuteScalar(DbTransaction transaction, string xmlFileName, string sqlName, params object[] parValues)
        {
            return this.ExecuteScalar<object>(transaction, xmlFileName, sqlName, parValues);
        }

        public DataSet GetDataSetByXml(string xmlFileName, string sqlName, params object[] parValues)
        {
            return this.GetDataSetByXml(null, xmlFileName, sqlName, parValues);
        }

        public DataSet GetDataSetByXml(DbTransaction transaction, string xmlFileName, string sqlName, params object[] parValues)
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);
            TraceEx.Write("开始执行  MB.Orm.Persistence.PersistenceManagerHelper.NewInstance.CreateDbCommandByXml ");
            DbCommand[] commandArray = null;
            try
            {
                if (this._PersistenceManager == null)
                {
                    this._PersistenceManager = new PersistenceManagerHelper(this._CommandTextFormatValues);
                }
                commandArray = this._PersistenceManager.CreateDbCommandByXml(db, xmlFileName, sqlName, parValues);
            }
            catch (Exception exception)
            {
                throw new APPException(exception);
            }
            if (commandArray.Length != 1)
            {
                throw new SelectSqlXmlConfigException(xmlFileName, sqlName);
            }
            DbCommand dbCmd = commandArray[0];
            TraceEx.Write("正在执行:" + DbCommandExecuteTrack.Instance.CommandToTrackMessage(db, dbCmd));
            DataSet set = new DataSet();
            try
            {
                set = (transaction == null) ? db.ExecuteDataSet(dbCmd) : db.ExecuteDataSet(dbCmd, transaction);
            }
            catch (Exception exception2)
            {
                throw new DatabaseExecuteException("执行GetDataSetByXml 出错！", exception2);
            }
            finally
            {
                foreach (DbCommand command2 in commandArray)
                {
                    command2.Dispose();
                }
            }
            return set;
        }

        public DataSet GetDataSetByXmlParams(string xmlFileName, string sqlName, QueryParameterInfo[] parInfos)
        {
            return this.GetDataSetByXmlParams(null, xmlFileName, sqlName, parInfos);
        }

        public DataSet GetDataSetByXmlParams(DbTransaction transaction, string xmlFileName, string sqlName, QueryParameterInfo[] parInfos)
        {
            QueryParameterMappings sqlQueryParamMappings = SqlConfigHelper.Instance.GetSqlQueryParamMappings(xmlFileName, sqlName);
            string str = SqlShareHelper.Instance.QueryParametersToSqlString(sqlQueryParamMappings, parInfos);
            return this.GetDataSetByXml(transaction, xmlFileName, sqlName, new object[] { str });
        }

        public List<T> GetObjectsByXml<T>(string xmlFileName, string sqlName, params object[] parValues)
        {
            List<T> list;
            try
            {
                Type cfgEntityType = typeof(T);
                list = this.GetObjectsByXml<T>(cfgEntityType, xmlFileName, sqlName, parValues);
            }
            catch (Exception exception)
            {
                throw new APPException(exception);
            }
            return list;
        }

        public List<T> GetObjectsByXml<T>(Type cfgEntityType, string xmlFileName, string sqlName, params object[] parValues)
        {
            return this.GetObjectsByXml<T>(null, cfgEntityType, xmlFileName, sqlName, parValues);
        }

        public List<T> GetObjectsByXml<T>(QueryParameterMappings parsMapping, string xmlFileName, string sqlName, QueryParameterInfo[] parInfos, params object[] parValues)
        {
            List<T> list2;
            try
            {
                QueryParameterMappings sqlQueryParamMappings = parsMapping;
                if (sqlQueryParamMappings == null)
                {
                    sqlQueryParamMappings = SqlConfigHelper.Instance.GetSqlQueryParamMappings(xmlFileName, sqlName);
                }
                string item = SqlShareHelper.Instance.QueryParametersToSqlString(sqlQueryParamMappings, parInfos);
                List<object> list = new List<object>();
                if ((parValues != null) && (parValues.Length > 0))
                {
                    foreach (object obj2 in parValues)
                    {
                        list.Add(obj2);
                    }
                }
                list.Add(item);
                list2 = this.GetObjectsByXml<T>(xmlFileName, sqlName, list.ToArray());
            }
            catch (Exception exception)
            {
                throw new APPException("执行GetObjectsByXml<T> 出错", APPMessageType.SysDatabaseInfo, exception);
            }
            return list2;
        }

        public List<T> GetObjectsByXml<T>(DbTransaction transaction, Type cfgEntityType, string xmlFileName, string sqlName, params object[] parValues)
        {
            Database db = DatabaseHelper.CreateDatabase(_ormP);
            if (this._PersistenceManager == null)
            {
                this._PersistenceManager = new PersistenceManagerHelper(this._CommandTextFormatValues);
            }
            DbCommand[] commandArray = this._PersistenceManager.CreateDbCommandByXml(db, xmlFileName, sqlName, parValues);
            if (commandArray.Length != 1)
            {
                throw new SelectSqlXmlConfigException(xmlFileName, sqlName);
            }
            DbCommand dbCmd = commandArray[0];
            Type t = cfgEntityType;
            bool flag = t.IsSubclassOf(typeof(BaseModel));
            AttMappingManager instance = AttMappingManager.Instance;
            List<FieldPropertyInfo> list = instance.CheckExistsModelMapping(t) ? instance.GetModelMappingInfo(t).FieldPropertys.Values.ToList<FieldPropertyInfo>() : instance.GetEntityMappingPropertys(t);
            List<T> list2 = new List<T>();
            TraceEx.Write("正在执行:" + DbCommandExecuteTrack.Instance.CommandToTrackMessage(db, dbCmd));
            using (IDataReader reader = (transaction == null) ? db.ExecuteReader(dbCmd) : db.ExecuteReader(dbCmd, transaction))
            {
                try
                {
                    try
                    {
                        DataTable schemaTable = reader.GetSchemaTable();
                        Dictionary<string, DynamicPropertyAccessor> dictionary = new Dictionary<string, DynamicPropertyAccessor>();
                        foreach (FieldPropertyInfo info in list)
                        {
                            if (schemaTable.Select(string.Format("ColumnName='{0}'", info.FieldName)).Length > 0)
                            {
                                PropertyInfo property = t.GetProperty(info.PropertyName);
                                if (property != null)
                                {
                                    DynamicPropertyAccessor accessor = new DynamicPropertyAccessor(t, property);

                                    if (!dictionary.Keys.Contains(info.FieldName))
                                    {
                                        dictionary.Add(info.FieldName, accessor);
                                    }
                                }
                            }
                        }
                        if (dictionary.Count > 0)
                        {
                            while (reader.Read())
                            {
                                try
                                {
                                    T target = (T)Reflection.CreateObjectInstance(t);
                                    foreach (KeyValuePair<string, DynamicPropertyAccessor> pair in dictionary)
                                    {
                                        try
                                        {
                                            object obj2 = reader[pair.Key];
                                            if ((obj2 != null) && (obj2 != DBNull.Value))
                                            {
                                                dictionary[pair.Key].Set(target, obj2);
                                            }
                                            continue;
                                        }
                                        catch (Exception exception)
                                        {
                                            throw new APPException(string.Format("执行GetObjectsByXml 设置 {0} 的值 时出错.", pair.Key) + exception.Message, APPMessageType.SysErrInfo);
                                        }
                                    }
                                    if (flag)
                                    {
                                        BaseModel model = target as BaseModel;
                                        model.EntityState = EntityState.Persistent;
                                    }
                                    list2.Add(target);
                                    continue;
                                }
                                catch (Exception exception2)
                                {
                                    throw new APPException(string.Format("循环读取第{0} 个实体对象时出错.当前数据库Connection 状态[{1}] ", list2.Count, dbCmd.Connection.State.ToString()) + exception2.Message, APPMessageType.SysErrInfo);
                                }
                            }
                        }
                        return list2;
                    }
                    catch (Exception exception3)
                    {
                        throw new DatabaseExecuteException("执行GetObjectsByXml<" + t.FullName + "> 出错！", exception3);
                    }
                    return list2;
                }
                finally
                {
                    foreach (DbCommand command2 in commandArray)
                    {
                        command2.Dispose();
                    }
                }
            }
            return list2;
        }

        // Properties
        public static DatabaseExcuteByXmlHelper NewInstance
        {
            get
            {
                return new DatabaseExcuteByXmlHelper(new string[0]);
            }
        }

        public static DatabaseExcuteByXmlHelper GetInstance(OrmConnectionParams ormP = null)
        {
            //get
            //{
            //    return new DatabaseExcuteByXmlHelper()
            //}
            return new DatabaseExcuteByXmlHelper(ormP);
        }
    }
}
